#pragma once

#include <iostream>
#include <cerrno>
#include "Connection.hpp"
#include "include/Protocol.hpp"
#include "include/CalculateService.hpp"

class EventHandler
{
public:
    EventHandler()
    {}

    static void handlerRequest(Connection* conn)
    {
        std::string& inBuffer = conn->getInBuffer();
        std::string content;
        DLP::ReqRespFactory factory;
        CalculateService calculateService;
        while(DLP::dlpDecoding(inBuffer, content))
        {
            std::shared_ptr<DLP::Request> req = factory.makeRequest();
            if(req->deserialize(content)) 
            {
                int code = -1;
                int result = calculateService.doCalculate(req->getX(), req->getY(), req->getOp(), code);
                std::shared_ptr<DLP::Response> resp = factory.makeResponse(result, code);
                std::string dlpResponse = DLP::dlpEncoding(resp->serialize());
                conn->appendOutBuffer(dlpResponse);
            }
        }
        if(!conn->isOutBufferEmpty())
        {
            write(conn);
        }
    }

    static void read(Connection* conn)
    {
        char buffer[1024];
        while(true)
        {
            // 只负责把本轮数据读尽，不关心数据的格式/协议
            ssize_t n = ::read(conn->getSockFd(), buffer, sizeof(buffer)-1);
            if(n > 0)
            {
                buffer[n] = '\0';
                conn->appendInBuffer(buffer);
            }
            else
            {
                if(errno == EAGAIN) break; //数据取尽，无数据就绪
                else if(errno == EINTR) continue; //上次读取被信号中断
                else //发生错误
                {
                    except(conn);
                    log.message(WARN, "read error... %d: %s", errno, strerror(errno));
                    return;
                }
            }
        }
        std::cout << "fd# " << conn->getSockFd() << std::endl << "接收缓冲区：" << conn->getInBuffer() << std::endl;
        // EAGAIN
        handlerRequest(conn);
    }

    static void write(Connection* conn)
    {
        std::string& outBuffer = conn->getOutBuffer();
        while(true)
        {
            ssize_t n = ::write(conn->getSockFd(), outBuffer.c_str(), outBuffer.size());
            if(n > 0)
            {
                outBuffer.erase(0, n); //已经发送的，从缓冲区移除
                if(outBuffer.empty()) break;
            }
            else
            {
                if(errno == EAGAIN) break;
                else if(errno == EINTR) continue;
                else
                {
                    except(conn);
                    log.message(WARN, "write error... %d: %s", errno, strerror(errno));
                    return;
                }
            }
        }

        // 写事件按需关心
        if(conn->isOutBufferEmpty())
        {
            // outBuffer.empty()跳出，数据发完，关闭对写事件的关心
            conn->_svrFrom->enableEvent(conn->getSockFd(), true, false);
        }
        else
        {
            // EAGAIN跳出，内核发送缓冲区写满，开启对写事件EPOLLOUT的关心
            // 写事件一旦就绪（内核缓冲区腾出空间），会通过事件派发器再次回调到此方法，发送剩余数据
            conn->_svrFrom->enableEvent(conn->getSockFd(), true, true);
        }
    }

    static void except(Connection* conn)
    {
        log.message(INFO, "connection erase, fd: %d", conn->getSockFd());
        // epoll中移除红黑树节点
        // unordered_map中移除conn项
        conn->_svrFrom->removeConnection(conn);
        // 关fd
        conn->closeFd();
        // 删conn
        delete conn;
    }

    ~EventHandler()
    {}
};